home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 27 / CU Amiga Magazine's Super CD-ROM 27 (1998)(EMAP Images)(GB)[!][issue 1998-10].iso / CUCD / Sound / SPlayer / Socks5 / src / lib / buffer.c < prev    next >
C/C++ Source or Header  |  1998-07-20  |  10KB  |  325 lines

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6.  
  7. /*
  8.  * $Id: buffer.c,v 1.51.4.3 1998/07/17 19:56:20 wlu Exp $
  9.  */
  10.  
  11. #include "socks5p.h"
  12. #include "buffer.h"
  13. #include "block.h"
  14. #include "addr.h"
  15. #include "log.h"
  16. #include "msg.h"
  17.  
  18. #define DATAHEAD(b) ((b)->data + (b)->off)
  19. #define DATASIZE(b) ((b)->len  - (b)->off)
  20.  
  21. static int S5BufFillPacket(S5Packet *ebuf, char *buffer, int buflen, int ioflags) {
  22.     int len = DATASIZE(ebuf);
  23.  
  24.     if (len <= 0) return 0;
  25.     if (len > buflen) len = buflen;
  26.     
  27.     memcpy(buffer, DATAHEAD(ebuf), len);
  28.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufFill: Filled in %d bytes out of buffer", len);
  29.  
  30.     if (ioflags & MSG_PEEK) return len;
  31.     ebuf->off += len;
  32.  
  33.     if (DATASIZE(ebuf) > 0) {
  34.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufFill: Leaving %d bytes in buffer", DATASIZE(ebuf));
  35.     } else {
  36.     free(ebuf->data);
  37.  
  38.     ebuf->data = NULL;
  39.     ebuf->off  = 0;
  40.     ebuf->len  = 0;
  41.     }
  42.  
  43.     return len;
  44. }
  45.  
  46. static int S5BufPutPacket(S5IOHandle fd, char *buffer, int buflen, int ioflags) {
  47.     int n, m = buflen;
  48.     fd_set fds, wfs;
  49.     struct timeval *stm, tm = { 0, 0 };
  50.  
  51.     FD_ZERO(&wfs);
  52.     FD_SET(fd, &wfs);
  53.     if (ISNBLOCK(fd)) stm = &tm;
  54.     else          stm = NULL;
  55.  
  56.     while (m > 0) {
  57.     fds = wfs;
  58.     switch (REAL(select)(fd + 1, NULL, &fds, NULL, stm)) {
  59.         case -1:
  60.             if (ISSOCKETERROR(EINTR)) continue;
  61.         else {
  62.                     SETSOCKETERROR(EBADF);
  63.             return -1;
  64.             }
  65.         case 0:
  66.         if (m == buflen) {
  67.  
  68. #if defined(sun) && !defined(__svr4__)
  69.                     SETSOCKETERROR(EWOULDBLOCK);
  70. #else
  71.                     SETSOCKETERROR(EAGAIN);
  72. #endif
  73.             return -1;
  74.          }
  75.  
  76.         stm = NULL;
  77.         continue;
  78.     }
  79.  
  80.     if ((n = SENDSOCKET(fd, buffer, m, ioflags)) < 0) {
  81.             if (S5IOCheck(fd) >= 0) continue;
  82.             else {
  83.                 SETSOCKETERROR(EBADF);
  84.                 return -1;
  85.             }
  86.     }
  87.  
  88.     m -= n;
  89.     buffer += n;
  90.     }
  91.  
  92.     return 0;
  93. }
  94.  
  95. static int S5BufGetPacket(S5IOHandle fd, S5IOInfo *cinfo, int block) {
  96.     int nlen, nr;
  97.     S5Packet buf;
  98.     char *nbuf;
  99.     
  100.     if (cinfo->ibuf.data == NULL) {
  101.     cinfo->ibuf.off = 0;
  102.     cinfo->ibuf.len = 0;
  103.     }
  104.  
  105.     while (1) {
  106.     /* As long as we haven't read in the whole packet, read in more...   */
  107.     buf.data = cinfo->ibuf.data;
  108.     buf.len  = cinfo->ibuf.off;
  109.  
  110.     if (!(nlen = cinfo->auth.check(&buf, cinfo->auth.context))) {
  111.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufGet: Whole packet available...");
  112.         return 1;
  113.     }
  114.  
  115.     /* Grow the buffer if necessary...                                   */
  116.     if (cinfo->ibuf.len < cinfo->ibuf.off + nlen) {
  117.         if (!cinfo->ibuf.data) nbuf = (char *)malloc(cinfo->ibuf.off + nlen);
  118.         else                   nbuf = (char *)realloc(cinfo->ibuf.data, cinfo->ibuf.off + nlen);
  119.  
  120.         if (!nbuf) {
  121.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5BufGet: Out of memory enlarging packet buffer");
  122.         SETSOCKETERROR(EBADF);        
  123.         return -1;
  124.         }
  125.  
  126.         cinfo->ibuf.len  = cinfo->ibuf.off + nlen;
  127.         cinfo->ibuf.data = nbuf;
  128.     }
  129.  
  130.         if (!block) {
  131.             int na = 0;
  132.  
  133.             if (S5IOCheck(fd) < 0) return 0;
  134. #ifdef FIONREAD
  135.             if ((nr = IOCTLSOCKET(fd, FIONREAD, &na)) < 0) {
  136.                 SETSOCKETERROR(EBADF);
  137.                 return -1;
  138.             }
  139.  
  140.             if (na < nlen) {
  141.                 S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufGet: Not enough data");
  142. #if defined(sun) && !defined(__svr4__)
  143.                 SETSOCKETERROR(EWOULDBLOCK);
  144. #else
  145.                 SETSOCKETERROR(EAGAIN);
  146. #endif
  147.                 return -2;
  148.         }
  149. #endif
  150.         }
  151.  
  152.     switch (nr = RECVSOCKET(fd, cinfo->ibuf.data + cinfo->ibuf.off, nlen, 0)) {
  153.         case -1:
  154.          if (ISSOCKETERROR(EINTR)) continue;
  155.         case 0:
  156.         return nr;
  157.     }
  158.  
  159.     /* Update counters...                                                */
  160.     cinfo->ibuf.off += nr;
  161.     }
  162.  
  163.     SETSOCKETERROR(EBADF);
  164.     return -1;
  165. }
  166.     
  167. /* Check if whole packet is available including data in the I/O buffer       */
  168. /* Return 1 if packet is available, -2 if not available and 0/-1 if I/O      */
  169. /* fails...                                                                  */
  170. int S5BufCheckPacket(S5IOHandle fd, S5IOInfo *cinfo) {
  171.     /* If there's no buffering, or if we've read the whole thing, we're done */
  172.     if (!cinfo || !cinfo->auth.check) return 1;
  173.  
  174.     return S5BufGetPacket(fd, cinfo, 0);
  175. }
  176.  
  177. /* Check if whole packet is available in the buffer. Return 1 if packet is   */
  178. /* available, 0 if not.                                                      */
  179. int S5BufCheckData(S5IOHandle fd, S5IOInfo *cinfo) {
  180.     if (cinfo && cinfo->obuf.data) return 1;
  181.     return 0;
  182. }
  183.  
  184. int S5BufUnreadPacket(S5IOInfo *cinfo, char *ibuf, int ilen) {
  185.     S5Packet nbuf;
  186.     
  187.     if (!cinfo || ilen < 0) return -1;
  188.     if (ilen == 0) return 0;
  189.  
  190.     if (!cinfo->obuf.data) {
  191.     cinfo->obuf.len  = 0;
  192.     cinfo->obuf.off  = 0;
  193.     }
  194.  
  195.     /* Try to put the data back into the buffer...                           */
  196.     if (cinfo->obuf.off >= ilen) {
  197.     memcpy(DATAHEAD(&cinfo->obuf) - ilen, ibuf, ilen);
  198.     cinfo->obuf.off -= ilen;
  199.     return 0;
  200.     }
  201.  
  202.     /* Make a new buffer which can hold what was already there and this.     */
  203.     nbuf.len  = DATASIZE(&cinfo->obuf) + ilen;
  204.     nbuf.off  = 0;
  205.     
  206.     if (!(nbuf.data = (char *)malloc(nbuf.len * sizeof(char)))) {
  207.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "S5BufUnread: Couldn't allocate buffer");
  208.     return -1;
  209.     }
  210.  
  211.     /* Put the already read data at the beginning of the buffer...           */
  212.     memcpy(DATAHEAD(&nbuf), ibuf, ilen);
  213.     nbuf.off  = ilen;
  214.  
  215.     /* There was already some data there, so copy it in...                   */
  216.     if (cinfo->obuf.data) {
  217.     memcpy(DATAHEAD(&nbuf), DATAHEAD(&cinfo->obuf), DATASIZE(&cinfo->obuf));
  218.     nbuf.off += DATASIZE(&cinfo->obuf);
  219.     }
  220.  
  221.     free(cinfo->obuf.data);
  222.     cinfo->obuf = nbuf;
  223.     return 0;
  224. }
  225.  
  226. int S5BufReadPacket(S5IOHandle fd, S5IOInfo *cinfo, char *ibuf, int ilen, int ioflags) {
  227.     int rval;
  228.     int block = (ISNBLOCK(fd))?0:1;
  229.  
  230.     if (!cinfo || !cinfo->auth.encode || ilen <= 0) {
  231.     return (int)RECVSOCKET(fd, ibuf, ilen, ioflags);
  232.     }
  233.     
  234.     /* Find out if there was a prior message we had read in an decoded, but  */
  235.     /* couldn't fit into the requested buffer...(this would be typical of a  */
  236.     /* program that calls do (read(fd, buf, 1) while (*buf++ != '\0'), or    */
  237.     /* the like... Also could occur if EINTR occured and restarting wasn't   */
  238.     /* set in S5IORecv...                                                    */
  239.     if (cinfo && cinfo->obuf.data != NULL) {
  240.     return S5BufFillPacket(&cinfo->obuf, (char *)ibuf, ilen, ioflags);
  241.     }
  242.  
  243.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufRead: encapsulated...");
  244.     
  245.     switch ((rval = S5BufGetPacket(fd, cinfo, block))) {
  246.     case -2: rval = -1;
  247.     case -1:
  248.     case  0: return rval;
  249.     default: break;
  250.     }
  251.  
  252.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufRead: Decoding message...");
  253.  
  254.     /* Decode message.  Again, if something goes wrong, we have no choice    */
  255.     /* but tho close the file descriptor (since its state is screwed up),    */
  256.     /* and return EBADF.                                                     */
  257.     if (cinfo->auth.encode(&cinfo->ibuf, &cinfo->obuf, S5_DECODE, cinfo->auth.context) < 0) {
  258.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S5BufRead: Decoding failed.");
  259.     SETSOCKETERROR(EBADF);
  260.     return -1;
  261.     }
  262.  
  263.     cinfo->obuf.off = 0;
  264.     free(cinfo->ibuf.data);
  265.     cinfo->ibuf.data = NULL;
  266.     
  267.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufRead: Done");
  268.     return S5BufFillPacket(&cinfo->obuf, ibuf, ilen, ioflags);
  269. }
  270.  
  271. int S5BufWritePacket(S5IOHandle fd, S5IOInfo *cinfo, char *obuf, int olen, int ioflags) {
  272.     S5Packet buf[2];
  273.     int elen;
  274.  
  275.     if (!cinfo || !cinfo->auth.encode || olen <= 0) {
  276.     return SENDSOCKET(fd, obuf, olen, ioflags);
  277.     }
  278.     
  279.     buf[0].data = obuf; buf[0].len = olen; buf[0].off = olen;
  280.     buf[1].data = NULL; buf[1].len = 0;       buf[1].off = 0;
  281.     
  282.     if ((elen = cinfo->auth.encode(&buf[0], &buf[1], S5_ENCODE, cinfo->auth.context)) < 0) {
  283.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: encapsulating packet failed");
  284.     SETSOCKETERROR(EBADF);
  285.     return -1;
  286.     }
  287.     
  288.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: Sending encapsulated packet");
  289.  
  290.     /* An easy thing to do is make sure we can write the whole message by    */
  291.     /* making the file descriptor blocking...ugh.                            */
  292.     elen = S5BufPutPacket(fd, buf[1].data, buf[1].len, ioflags);
  293.     free(buf[1].data);
  294.  
  295.     if (elen < 0) {
  296.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: Network failure");
  297.     return -1;
  298.     } else {
  299.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "S5BufWrite: Done");
  300.         return olen;
  301.     }
  302. }
  303.  
  304. void S5BufSetupContext(S5IOInfo *cinfo) {
  305.     cinfo->fd           = S5InvalidIOHandle;
  306.     cinfo->ibuf.data    = NULL;
  307.     cinfo->obuf.data    = NULL;
  308.     cinfo->auth.context = NULL;
  309.     cinfo->auth.clean   = NULL;
  310.     cinfo->auth.encode  = NULL;
  311.     cinfo->auth.check   = NULL;
  312. }
  313.  
  314. void S5BufCleanContext(S5IOInfo *cinfo) {
  315.     if (!cinfo) return;
  316.     
  317.     if (cinfo->auth.clean) cinfo->auth.clean(cinfo->auth.context);
  318.     if (cinfo->fd != S5InvalidIOHandle) CLOSESOCKET(cinfo->fd);
  319.     if (cinfo->ibuf.data) free(cinfo->ibuf.data);
  320.     if (cinfo->obuf.data) free(cinfo->obuf.data);
  321.  
  322.     S5BufSetupContext(cinfo);
  323. }
  324.  
  325.